// Package ioc
/**
* @Project : geektime-basic-go-study
* @File    : config.go
* @IDE     : GoLand
* @Author  : Tvux
* @Date    : 2024/11/4 09:24
**/

package ioc

import (
	"bytes"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	_ "github.com/spf13/viper/remote"
	"log"
)

// ReadConfigV1 viper使用示例
func ReadConfigV1() {
	// 默认配置
	viper.SetDefault("config.dbConf.dsn", "root:root@tcp(localhost:13316)/webook")
	// 设置配置文件的相对路径，相对于当前工作路径（注意）
	viper.AddConfigPath("./config")
	// 设置配置文件的文件名，不包含文件后缀名
	viper.SetConfigName("dev")
	// 设置配置文件的格式 yaml json toml ini...
	viper.SetConfigType("yaml")

	// 读取配置
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}

	// 因为viper读取的配置是存放到一个全局包变量viper中的，所以如果有别的模块想专门读取配置的话
	// 比如用户模块配置，文章模块配置，可以这样
	userConfViper := viper.New()
	userConfViper.AddConfigPath("./config")
	userConfViper.SetConfigName("user_dev")
	userConfViper.SetConfigType("json")
	if err := userConfViper.ReadInConfig(); err != nil {
		panic(err)
	}
	log.Println(userConfViper.GetString("name"))  // Output: Tvux
	log.Println(userConfViper.GetString("phone")) // Output: 18912345678
}

// ReadDevConfig 读取开发环境中的配置
func ReadDevConfig() {
	// 默认配置
	viper.SetDefault("config.dbConf.dsn", "root:root@tcp(localhost:13316)/webook")
	viper.SetDefault("config.redisConf.dsn", "localhost:6379")
	viper.SetDefault("config.authConf.secretKey", "aFZv0pTGcRVgaYIbMsNLT4xH53T6LkP6pqHHIcfeXMprDI8paZ8d1ERF6Une3KNBl6cuydFg8Oe2eHOJOhEWquza7vuL9eeaWlxK7fIm7m2JbODwYTsFJmyaQwz9r8XsrsCd2ASayV0wb30n3yZSOGaFlcfYsluIxJUYcGiP76VOQ2AVSZKzC1UU9RLmQg0J7sAWPe34IRe49cE4QyHqDvf8kFCgo0EIeKmeNbxkWIdD6vQulDPKq9QYxQU3VmI6")
	viper.Set("config.secure", false)
	viper.Set("config.httpOnly", false)
	// 直接设置配置文件的路径
	viper.SetConfigFile("./config/dev.yaml")

	// 读取配置
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}
}

// ReadK8sConfig 读取生产环境中的配置
func ReadK8sConfig() {
	// 默认配置
	viper.SetDefault("config.dbConf.dsn", "root:root@tcp(mysql:13316)/webook")
	viper.SetDefault("config.redisConf.dsn", "webook-redis:6379")
	viper.SetDefault("config.authConf.secretKey", "aFZv0pTGcRVgaYIbMsNLT4xH53T6LkP6pqHHIcfeXMprDI8paZ8d1ERF6Une3KNBl6cuydFg8Oe2eHOJOhEWquza7vuL9eeaWlxK7fIm7m2JbODwYTsFJmyaQwz9r8XsrsCd2ASayV0wb30n3yZSOGaFlcfYsluIxJUYcGiP76VOQ2AVSZKzC1UU9RLmQg0J7sAWPe34IRe49cE4QyHqDvf8kFCgo0EIeKmeNbxkWIdD6vQulDPKq9QYxQU3VmI6")
	viper.Set("config.secure", true)
	viper.Set("config.httpOnly", true)
	// 直接设置配置文件的路径
	viper.SetConfigFile("./config/k8s.yaml")

	// 读取配置
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}
}

// ReadConfigFromReader 从 io.Reader 中读取配置
func ReadConfigFromReader() {
	viper.SetConfigType("yaml")
	conf := `
# dev.yaml
config:
  dbConf:
    dsn: "root:root@tcp(localhost:13316)/webook"
  redisConf:
    dsn: "localhost:6379"
  authConf:
    secretKey: "aFZv0pTGcRVgaYIbMsNLT4xH53T6LkP6pqHHIcfeXMprDI8paZ8d1ERF6Une3KNBl6cuydFg8Oe2eHOJOhEWquza7vuL9eeaWlxK7fIm7m2JbODwYTsFJmyaQwz9r8XsrsCd2ASayV0wb30n3yZSOGaFlcfYsluIxJUYcGiP76VOQ2AVSZKzC1UU9RLmQg0J7sAWPe34IRe49cE4QyHqDvf8kFCgo0EIeKmeNbxkWIdD6vQulDPKq9QYxQU3VmI6"
  secure: false
  httpOnly: false
`
	err := viper.ReadConfig(bytes.NewReader([]byte(conf)))
	if err != nil {
		panic(err)
	}
}

// ReadConfigFromCmd 从命令行参数读取配置
func ReadConfigFromCmd() {
	confFile := pflag.String("config", "config/dev.yaml", "配置文件的路径")
	pflag.Parse()
	viper.SetConfigFile(*confFile)

	// 实时监听配置文件变更
	// 注意这里的调用顺序，WatchConfig必须在OnConfigChange和ReadInConfig之前
	// 需要注意的是，如果是监听远程配置中心的变更 WatchRemoteConfig
	// 并不能通过 OnConfigChange 知道远程配置中心的配置改动，因为这个是监听 “文件” 的
	viper.WatchConfig()
	viper.OnConfigChange(func(in fsnotify.Event) {
		// 这里只能知道配置文件变更了，但是变更的内容不知道
		fmt.Println(in.Name, in.Op)
	})

	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
}

// ReadConfigFromRemote 从远程配置中心读取配置
func ReadConfigFromRemote() {
	viper.SetConfigType("yaml")
	err := viper.AddRemoteProvider("etcd3", "127.0.0.1:2379", "/webook")
	if err != nil {
		panic(err)
	}
	err = viper.ReadRemoteConfig()
	if err != nil {
		panic(err)
	}
}
